package com.owg.jigsaw.cutEditor;

public class UndoManager
{	
	private Runnable[] undos;
	private Runnable[] redos;
	private String[] messages;
	private int maxSize;
	private int currentSize;
	private int nextIndex;
	private int remainingRedos;
	private int remainingUndos;
	
	private boolean isPerforming = false;
	
	public UndoManager(int maxSize)
	{
		this.maxSize = maxSize;
		undos = new Runnable[maxSize];
		redos = new Runnable[maxSize];
		messages = new String[maxSize];
		currentSize = 0;
		nextIndex = 0;
		remainingRedos = 0;
		remainingUndos = 0;
	}
	
	public boolean canUndo()
	{
		return remainingUndos > 0;
	}
	public boolean canRedo()
	{
		return remainingUndos > 0;
	}
	public String redo()
	{
		if(remainingRedos > 0)
		{
			isPerforming = true;
			String msg = messages[nextIndex];
			redos[nextIndex].run();
			remainingUndos++;
			remainingRedos--;
			nextIndex = cycle(nextIndex+1, maxSize);
			isPerforming = false;
			return msg;
		}
		return null;
	}
	public String undo()
	{
		if(remainingUndos > 0)
		{
			isPerforming = true;
			String msg = messages[cycle(nextIndex-1, maxSize)];
			undos[cycle(nextIndex-1, maxSize)].run();
			remainingUndos--;
			remainingRedos++;
			nextIndex = cycle(nextIndex-1, maxSize);
			isPerforming = false;
			return msg;
		}
		return null;
	}
	public boolean isPerforming()
	{
		return isPerforming;
	}
	
	private int cycle(int value, int max)
	{
		return ((value%max)+max)%max;
	}

	public void logUndo(Runnable undo, Runnable redo, String message)
	{
		System.out.println("Operation: "+message);
		if(currentSize < maxSize)
			currentSize++;
		if(remainingUndos < maxSize)
			remainingUndos++;
		remainingRedos = 0;//All redos are killed by an operation
		this.redos[nextIndex] = redo;
		this.undos[nextIndex] = undo;
		this.messages[nextIndex] = message;
		nextIndex = cycle(nextIndex+1, maxSize);
	}
}
